﻿using System;
using System.Collections.Generic;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DataAccess.Tests
{
    [TestClass()]
    public class PolymorphicUsageTest
    {
        private TestContext testContextInstance;

        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //Use ClassInitialize to run code before running the first test in the class
        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            // If there are no records then create them
            var cr = Factory.Command()
                .Connection(connectionName)
                .Text("SELECT COUNT(1) FROM Person")
                .ExecuteScalar<int>();

            if (cr.Data == 0)
            {
                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pEmployee_Insert")
                .Parameter("personName", "Gilberto Santa Rosa")
                .Parameter("salary", 1800000.00m)
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pEmployee_Insert")
                .Parameter("personName", "Gloria Stefan")
                .Parameter("salary", 1500000.00m)
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pEmployee_Insert")
                .Parameter("personName", "Willy Chirino")
                .Parameter("salary", 1000000.00m)
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pCustomer_Insert")
                .Parameter("personName", "Barack Obama")
                .Parameter("credit", 1000000.00m)
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pCustomer_Insert")
                .Parameter("personName", "Bill Gates")
                .Parameter("credit", 1500000.00m)
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pCustomer_Insert")
                .Parameter("personName", "Mike Jackson")
                .Parameter("credit", 1800000.00m)
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pPerson_Insert")
                .Parameter("personName", "Pablo Pueblo")
                .ExecuteNonQuery();

                Factory.Command()
                .Connection(connectionName)
                .StoredProcedure("pPerson_Insert")
                .Parameter("personName", "John Carpenter")
                .ExecuteNonQuery();
            }
        }
        
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        static readonly string connectionName = "SqlServerDataAccessTest.PolymorphicUsageTest.ConnectionString";

        internal class Person
        {
            public int Id { get; set; }

            public string PersonName { get; set; }
        }

        internal class Employee : Person
        {
            public decimal? Salary { get; set; }
        }

        internal class Customer : Person
        {
            public decimal? Credit { get; set; }
        }

        [TestMethod()]
        public void PolymorphicUsageCommandsTest()
        {
            var response = Factory
                .Command()
                .Connection(connectionName)
                .StoredProcedure("pPerson_List")
                .QueryCollection<Person>((reader, p) =>
                {
                    p.PersonName = reader.GetString(0);
                    p.Id = reader.GetInt32(1);

                    if (p is Customer)
                    {
                        Customer c = (Customer)p;
                        c.Credit = reader.GetDecimal(3);
                    }
                    else if (p is Employee)
                    {
                        Employee e = (Employee)p;
                        e.Salary = reader.GetDecimal(2);
                    }
                    else // p is a Person
                    {
                    }
                },
                typeMap: TypeMap.Map().Index(4)
                    .Type(1, typeof(Employee))
                    .Type(2, typeof(Customer))
                    .Type(3, typeof(Person))
                );

            IList<Person> people = response.Data;

            Employee employee = (Employee)people[0];
            Assert.AreEqual(1, employee.Id);
            Assert.AreEqual("Gilberto Santa Rosa", employee.PersonName);
            Assert.AreEqual(1800000.00m, employee.Salary);

            employee = (Employee)people[1];
            Assert.AreEqual(2, employee.Id);
            Assert.AreEqual("Gloria Stefan", employee.PersonName);
            Assert.AreEqual(1500000.00m, employee.Salary);

            employee = (Employee)people[2];
            Assert.AreEqual(3, employee.Id);
            Assert.AreEqual("Willy Chirino", employee.PersonName);
            Assert.AreEqual(1000000.00m, employee.Salary);

            Customer customer = (Customer)people[3];
            Assert.AreEqual(4, customer.Id);
            Assert.AreEqual("Barack Obama", customer.PersonName);
            Assert.AreEqual(1000000.00m, customer.Credit);

            customer = (Customer)people[4];
            Assert.AreEqual(5, customer.Id);
            Assert.AreEqual("Bill Gates", customer.PersonName);
            Assert.AreEqual(1500000.00m, customer.Credit);

            customer = (Customer)people[5];
            Assert.AreEqual(6, customer.Id);
            Assert.AreEqual("Mike Jackson", customer.PersonName);
            Assert.AreEqual(1800000.00m, customer.Credit);

            Person person = people[6];
            Assert.AreEqual(7, person.Id);
            Assert.AreEqual("Pablo Pueblo", person.PersonName);

            person = people[7];
            Assert.AreEqual(8, person.Id);
            Assert.AreEqual("John Carpenter", person.PersonName);
        }

        [TestMethod()]
        public void PolymorphicUsageCommandsPropertyMapTest()
        {
            var response = Factory
                .Command()
                .Connection(connectionName)
                .StoredProcedure("pPerson_List")
                .QueryCollection<Person>(
                typeMap: TypeMap.Map().Index(4)
                            .Type(1, typeof(Employee))
                            .Type(2, typeof(Customer))
                            .Type(3, typeof(Person)),
                propertyMap: PropertyMap.Map()
                                //.Property("PersonName", 0)
                                .Property("Id", 1)
                                //.Property("Salary", 2)
                                //.Property("Credit", 3)
                                .Property("ItDoesNotExist", 4) // Ignored if it does not exist
                );

            IList<Person> people = response.Data;

            Employee employee = (Employee)people[0];
            Assert.AreEqual(1, employee.Id);
            Assert.AreEqual("Gilberto Santa Rosa", employee.PersonName);
            Assert.AreEqual(1800000.00m, employee.Salary);

            employee = (Employee)people[1];
            Assert.AreEqual(2, employee.Id);
            Assert.AreEqual("Gloria Stefan", employee.PersonName);
            Assert.AreEqual(1500000.00m, employee.Salary);

            employee = (Employee)people[2];
            Assert.AreEqual(3, employee.Id);
            Assert.AreEqual("Willy Chirino", employee.PersonName);
            Assert.AreEqual(1000000.00m, employee.Salary);

            Customer customer = (Customer)people[3];
            Assert.AreEqual(4, customer.Id);
            Assert.AreEqual("Barack Obama", customer.PersonName);
            Assert.AreEqual(1000000.00m, customer.Credit);

            customer = (Customer)people[4];
            Assert.AreEqual(5, customer.Id);
            Assert.AreEqual("Bill Gates", customer.PersonName);
            Assert.AreEqual(1500000.00m, customer.Credit);

            customer = (Customer)people[5];
            Assert.AreEqual(6, customer.Id);
            Assert.AreEqual("Mike Jackson", customer.PersonName);
            Assert.AreEqual(1800000.00m, customer.Credit);

            Person person = people[6];
            Assert.AreEqual(7, person.Id);
            Assert.AreEqual("Pablo Pueblo", person.PersonName);

            person = people[7];
            Assert.AreEqual(8, person.Id);
            Assert.AreEqual("John Carpenter", person.PersonName);
        }
    }
}
